package Main;

import java.util.*;

import Common.TacOperandType;
import Include.*;
import Common.*;

import static Common.REG.*;

public class SymbolManager {
    public String name_;
    public Scope global_scope_;
    public Scope local_scope_;
    public Symbol func_; // 假设func_是Symbol类型

    public List<String> rvalue_; // 地址-寄存器 -> 变量
    public List<String> svalue_; // 地址-内存 -> 变量
    public Map<String, REG> avalue_reg_; // 变量 -> 地址-寄存器
    public Map<String, Integer> avalue_mem_; // 变量 -> 地址-内存(存与ebp的偏移)

    public Map<String, UseInfo> useInfoMap; // 变量名 -> 符号表中的待用信息和活跃信息

    public int len_; // 当前栈的长度 (4 字节)
    public int stack_esp_; // 模拟堆栈的栈顶 (与当前函数栈底的相对值)
    public int para_num_;
    public int para_now_;
    public int ret_num_;
    public int ret_now_;
    public ArrayList<TACLine> TACBlock = new ArrayList<>();

    // 构造函数
    public SymbolManager(Scope global_scope, String name) {
        this.name_ = name;
        this.global_scope_ = global_scope;
        this.local_scope_ = null;
        int regCnts = REG.Cnts.getValue();
        rvalue_ = new ArrayList<>(Collections.nCopies(regCnts + 4, ""));
        this.svalue_ = new ArrayList<>();
        this.avalue_reg_ = new HashMap<>();
        this.avalue_mem_ = new HashMap<>();
        this.useInfoMap = new HashMap<>();

        this.len_ = 0;
        this.stack_esp_ = 0;
        this.para_num_ = 0;
        this.para_now_ = 0;
        this.ret_now_ = 0;
        this.ret_num_ = 0;
    }

    public String getName_() {
        return name_;
    }

    public void setName_(String name_) {
        this.name_ = name_;
    }

    public Scope getGlobal_scope_() {
        return global_scope_;
    }

    public void setGlobal_scope_(Scope global_scope_) {
        this.global_scope_ = global_scope_;
    }

    public Scope getLocal_scope_() {
        return local_scope_;
    }

    public void setLocal_scope_(Scope local_scope_) {
        this.local_scope_ = local_scope_;
    }

    public Symbol getFunc_() {
        return func_;
    }

    public void setFunc_(Symbol func_) {
        this.func_ = func_;
    }

    public List<String> getRvalue_() {
        return rvalue_;
    }

    public void setRvalue_(List<String> rvalue_) {
        this.rvalue_ = rvalue_;
    }

    public List<String> getSvalue_() {
        return svalue_;
    }

    public void setSvalue_(List<String> svalue_) {
        this.svalue_ = svalue_;
    }

    public Map<String, REG> getAvalue_reg_() {
        return avalue_reg_;
    }

    public void setAvalue_reg_(Map<String, REG> avalue_reg_) {
        this.avalue_reg_ = avalue_reg_;
    }

    public Map<String, Integer> getAvalue_mem_() {
        return avalue_mem_;
    }

    public void setAvalue_mem_(Map<String, Integer> avalue_mem_) {
        this.avalue_mem_ = avalue_mem_;
    }

    public Map<String, UseInfo> getUseInfoMap() {
        return useInfoMap;
    }

    public void setUseInfoMap(Map<String, UseInfo> useInfoMap) {
        this.useInfoMap = useInfoMap;
    }

    public int getLen_() {
        return len_;
    }

    public void setLen_(int len_) {
        this.len_ = len_;
    }

    public int getStack_esp_() {
        return stack_esp_;
    }

    public void setStack_esp_(int stack_esp_) {
        this.stack_esp_ = stack_esp_;
    }

    public int getPara_num_() {
        return para_num_;
    }

    public void setPara_num_(int para_num_) {
        this.para_num_ = para_num_;
    }

    public int getPara_now_() {
        return para_now_;
    }

    public void setPara_now_(int para_now_) {
        this.para_now_ = para_now_;
    }

    public int getRet_num_() {
        return ret_num_;
    }

    public void setRet_num_(int ret_num_) {
        this.ret_num_ = ret_num_;
    }

    public int getRet_now_() {
        return ret_now_;
    }

    public void setRet_now_(int ret_now_) {
        this.ret_now_ = ret_now_;
    }

    public void setScope(Scope scope) {
        this.local_scope_ = scope;
    }

    public String encodeVar(String var) {
        String enVar = "";
        if (var != null && !var.isEmpty() && !Character.isDigit(var.charAt(0))) {
            Symbol symbol = this.local_scope_.resolve(var);
            // 使用System.identityHashCode来获取symbol对象的唯一标识符
            enVar = String.format("%d:%s", System.identityHashCode(symbol), var);
        }
        return enVar;
    }

    public void setUseInfo(String variable, UseInfo useInfo) {
        String varEn = encodeVar(variable);
        if (varEn != null && !varEn.isEmpty()) {
            useInfoMap.put(varEn, useInfo);
        }
    }

    public UseInfo useInfo(String variable, boolean encoded) {
        String varEn = encoded ? variable : encodeVar(variable);
        return useInfoMap.getOrDefault(varEn, new UseInfo(0, false));
    }

    // 提供一个不指定encoded参数的重载方法
    public UseInfo useInfo(String variable) {
        // 默认encoded为false
        return useInfo(variable, false);
    }

    public void calUseInfo(List<TACLine> block) {
        // 初始化符号表中所有变量的待用信息
        useInfoMap.clear();
        UseInfo u;

        // 根据基本块出口来设置变量的活跃信息
        for (int i = block.size() - 1; i >= 0; i--) {
            TACLine line = block.get(i);
            this.setScope(line.scope);
            if (line.op == TacOp.FUN_RET) {
                u = new UseInfo(0, true);
                setUseInfo(line.src1.value, u);
            } else {
                break;
            }
        }

        // 从后往前遍历基本块，将变量的待用信息和活跃信息绑定在TACLine上
        for (int i = block.size() - 1; i >= 0; i--) {
            TACLine line = block.get(i);
            setScope(line.scope);

            if (line.op == TacOp.CALL) {
                continue;
            }

            if (line.getDst().getOperType() == TacOperandType.VAR) {
                // 把符号表中dst的待用信息和活跃信息附加到中间代码上
                line.dst.useInfo = this.useInfo(line.dst.value);
                // 重置符号表dst的待用信息和活跃信息
                u = new UseInfo(0, false);
                setUseInfo(line.getDst().getValue(), u);
            }

            if (line.getSrc1().getOperType() == TacOperandType.VAR) {
                // 把符号表中src1的待用信息和活跃信息附加到中间代码上
                line.src1.useInfo = this.useInfo(line.src1.value);
                // 置位符号表src1的待用信息和活跃信息
                u = new UseInfo(line.getLine(), true);
                setUseInfo(line.getSrc1().getValue(), u);
            }

            if (line.getSrc2() != null && line.getSrc2().getOperType() == TacOperandType.VAR) {
                // 把符号表中src2的待用信息和活跃信息附加到中间代码上
                line.src2.useInfo = this.useInfo(line.src2.value);
                // 置位符号表src2的待用信息和活跃信息
                u = new UseInfo(line.getLine(), true);
                setUseInfo(line.getSrc2().getValue(), u);
            }
        }
    }

    public REG getFreeReg() {
        for (int i = 0; i < REG.Cnts.value; i++) {
            if (rvalue_.get(i).equals("")) {
                return getMyReg(i);
            }
        }
        return REG.Cnts;
    }

    // 获取一个寄存器
    public REG getReg(String dst, String src1) {
        if (!dst.isEmpty() || !src1.isEmpty()) {
            if (!dst.isEmpty()) {
                if (avalue_reg_.containsKey(dst) && avalue_reg_.get(dst) != REG.Cnts) {
                    return avalue_reg_.get(dst);
                }
                if (avalue_mem_.containsKey(dst)) {
                    return REG.EDI;
                }
                if (!src1.isEmpty() && avalue_reg_.containsKey(src1) && avalue_reg_.get(src1) != REG.Cnts) {
                    return avalue_reg_.get(src1);
                }
            }
            return getFreeReg();
        } else {
            // 找到非活跃的寄存器
            return REG.ESI;
        }
    }

    public int avalueMem(String variable) {
        return avalue_mem_.getOrDefault(variable, -1);
    }

    public RelacedEeg getReplacedReg() {
        int cnts = REG.Cnts.value;

        // 寻找不再使用的变量
        for (int i = 0; i < cnts; i++) {
            String replacedVal = rvalue_.get(i);
            if (useInfoMap.containsKey(replacedVal) && useInfoMap.get(replacedVal).noUse()) {
                return new RelacedEeg(REG.getMyReg(i), replacedVal);
            }
        }

        // 寻找内存中有位置的变量
        for (int i = 0; i < cnts; i++) {
            String replacedVal = rvalue_.get(i);
            int valMem = this.avalueMem(replacedVal); // 假设avalueMem是一个返回int的方法
            if (valMem != -1) {
                return new RelacedEeg(REG.getMyReg(i), replacedVal, false, valMem);
            }
        }

        // 返回需要push备份的寄存器
        int maxNextUse = 0;
        REG maxNextUseReg = null;
        for (int i = 0; i < cnts; i++) {
            String enVar = rvalue(REG.getMyReg(i)); // 假设rvalue是一个接受REG并返回String的方法
            int nextUseI = useInfo(enVar, true).nextUse; // 假设use_info是一个返回某种类型的方法，该类型有nextUse属性
            if (maxNextUse < nextUseI) {
                maxNextUse = nextUseI;
                maxNextUseReg = REG.getMyReg(i);
            }
        }

        return new RelacedEeg(maxNextUseReg, rvalue(maxNextUseReg), false, -1);
    }

    public void setZeroLen() {
        this.len_ = 0;
    }

    public String rvalue(REG reg) {
        return (reg == null) ? "167sbmanger" : rvalue_.get(reg.value);
    }

    public REG avalueReg(String variable) {
        return avalue_reg_.getOrDefault(variable, REG.Cnts);
    }

    public int para() {
        int bias = -4 * (para_num_ - para_now_ + 1);
        para_now_ += 1;
        return bias;
    }

    public int ret() {
        int bias = -4 * (ret_num_ + para_num_ - ret_now_ + 1);
        ret_now_ += 1;
        return bias;
    }

    public Symbol resolveFun(String name) {
        // 假设local_scope_.resolve(name)返回一个包含Scope和Symbol的元组或类似的结构
        Symbol sy = local_scope_.resolve(name);
        if (sy.isFun()) {
            return sy;
        } else {
            return null;
        }
    }

    public void setAvalueReg(String variable, REG reg) {
        if (reg == null) {
            return;
        }
        String old = rvalue_.get(reg.value);
        if (old != null && avalue_reg_.get(old) == reg) {
            avalue_reg_.remove(old);
        }
        avalue_reg_.put(variable, reg);
        rvalue_.add(reg.value, variable);
    }

    public void setAvalueMem(String variable, int mem) {
        String old = svalue_.get(mem / 4);
        if (avalue_mem_.containsKey(old) && avalue_mem_.get(old) == mem) {
            avalue_mem_.remove(old);
        }
        avalue_mem_.put(variable, mem);
        svalue_.set(mem / 4, variable);
    }

    public void showReg(REG reg) {
        if (reg != REG.Cnts) {
            System.out.println(reg + ": " + rvalue_.get(reg.value));
        } else {
            for (int reg_i = 0; reg_i < REG.Cnts.value; reg_i++) {
                String en_var = rvalue_.get(reg_i);
                Integer var_next_use = useInfoMap.get(en_var).nextUse;
                System.out.println(REG.getMyReg(reg_i) + ": " + en_var + " " + var_next_use);
            }
        }
    }

    public void showMem(int mem) {
        System.out.println("len of mem: " + len_);
        for (Map.Entry<String, Integer> entry : avalue_mem_.entrySet()) {
            System.out.println("mem " + entry.getValue() + ": " + entry.getKey());
        }
    }

    public POSTYPE position(String variable) {
        if (variable == null || variable.isEmpty()) {
            return POSTYPE.GLOBAL;
        }

        int pos = variable.indexOf(":");
        String scope_str = variable.substring(0, pos);
//        String true_name = variable.substring(pos + 1);

        if (System.identityHashCode(global_scope_) == Integer.valueOf(scope_str)) {
            return POSTYPE.GLOBAL;
        } else if (avalue_reg_.containsKey(variable)) {
            return POSTYPE.REG;
        } else if (avalue_mem_.containsKey(variable)) {
            return POSTYPE.MEM;
        } else {
            return POSTYPE.NONE;
        }
    }

    public void pushReg(REG reg, int overwrite) {
        if (overwrite == 1) {
            if (reg == null) {
                return;
            }
            String var = rvalue_.get(reg.value);
            svalue_.add(var);
            avalue_mem_.put(var, stack_esp_);
        } else {
            svalue_.add("Null");
        }
        stack_esp_ += 4;
        len_ += 1;
    }

    public void popReg(REG reg) {
        String var = svalue_.remove(svalue_.size() - 1);
        String old = rvalue_.get(reg.value);
        if (old != null && avalue_reg_.get(old) == reg) {
            avalue_reg_.remove(old);
        }
        if (!var.equals("Null")) {
            avalue_reg_.put(var, reg);
            rvalue_.add(reg.value, var);
        }
        stack_esp_ -= 4;
        len_ -= 1;
    }

    public void setEspBias(int bias) {
        if (bias > 0) {
            int num = bias / 4;
            for (int i = 0; i < num; i++) {
                svalue_.add("Null");
            }
            len_ += num;
        } else {
            int num = Math.abs(bias) / 4;
            for (int i = 0; i < num; i++) {
                String old = svalue_.remove(svalue_.size() - 1);
                if (avalue_mem_.containsKey(old) && avalue_mem_.get(old) == stack_esp_ - (i + 1) * 4) {
                    avalue_mem_.remove(old);
                }
            }
            len_ -= num;
        }
        stack_esp_ += bias;
    }

    public int get_esp() {
        return stack_esp_;
    }

}